#ifndef __WM_CRYPTO_HARD_H__
#define __WM_CRYPTO_HARD_H__

#include "wm_hal.h"

#define CRYPTO		(CRYPTO_TypeDef *)CRYPTO_BASE				// CRYPTO register base address

/**************** CRC *****************/
typedef struct
{
	uint32_t value;					/*	INPUT: the initial value. OUTPUT: the result value. */
									
	uint32_t type;					/*	Specifies the CRC type.
									This parameter can be a value of @ref CRYPTO_CRC_TYPE */
									
	uint32_t mode;					/*	Specifies the CRC IN/OUT reverse.
									This parameter can be a value of @ref CRYPTO_CRC_IN_OUT_REVERSE */
	
} CRC_InitTypeDef;

typedef struct
{
	CRYPTO_TypeDef *Instance;
	CRC_InitTypeDef Init;
	
} CRC_HandleTypeDef;

// CRYPTO_CRC_TYPE
#define CRYPTO_CRC_TYPE_8 			CRYPTO_GPSEC_CFG_SUB_MODE_ECB
#define CRYPTO_CRC_TYPE_16_MODBUS	CRYPTO_GPSEC_CFG_SUB_MODE_CBC
#define CRYPTO_CRC_TYPE_16_CCITT	CRYPTO_GPSEC_CFG_SUB_MODE_CTR
#define CRYPTO_CRC_TYPE_32			CRYPTO_GPSEC_CFG_SUB_MODE_MAC

// CRYPTO_CRC_IN_OUT_REVERSE
#define OUTPUT_REFLECT 	CRYPTO_GPSEC_CFG_CRCOUT_REVERSE
#define INPUT_REFLECT 	CRYPTO_GPSEC_CFG_CRCIN_REVERSE



/**************** AES DES 3DES RC4 *****************/

#define AES_BLOCKEN	16
#define DES3_BLOCKLEN	8
#define DES3_KEY_LEN	24
#define DES3_IV_LEN		8
#define DES_KEY_LEN		8

typedef enum
{
	CRYPTO_WAY_ENCRYPT = 0,
	CRYPTO_WAY_DECRYPT,
	
} CRYPTO_WAY;

typedef enum
{
	CRYPTO_MODE_ECB = 0, // ECB
	CRYPTO_MODE_CBC,	 // CBC
	CRYPTO_MODE_CTR,	 // CTR, only for AES
	CRYPTO_MODE_CMAC,	 // MAC, only for AES
	
} CRYPTO_MODE;

typedef struct
{
	uint32_t skey[64];	// Key schedule (either encrypt or decrypt)
	uint16_t rounds;	// number of rounds
	uint16_t type;		// PS_AES_ENCRYPT or PS_AES_DECRYPT (inverse) key
	
} psAesKey_t;

typedef struct
{
	psAesKey_t key;
	unsigned char IV[AES_BLOCKEN];
	
} psAesCbc_t;

typedef struct
{
	uint8_t state[256];
	uint32_t byteCount;
	uint8_t x;
	uint8_t y;
	
} psArc4_t;

typedef struct
{
	uint32_t ek[3][32];
	uint32_t dk[3][32];
	
} psDes3Key_t;

typedef struct
{
	psDes3Key_t key;
	uint8_t IV[DES3_BLOCKLEN];
	uint32_t blocklen;
	
} psDes3_t;

typedef union
{
	psAesCbc_t aes;
	psArc4_t   arc4;
	psDes3_t   des3;
} Context_t;

typedef struct
{
	CRYPTO_TypeDef *Instance;
	Context_t u;
} psCipherContext_t;

HAL_StatusTypeDef HAL_CRYPTO_TRNG(uint8_t *out, uint32_t len);

HAL_StatusTypeDef HAL_CRYPTO_CRC_Init(CRC_HandleTypeDef *hcrytpo_crc, uint32_t key, uint32_t type, uint32_t mode);
HAL_StatusTypeDef HAL_CRYPTO_CRC_Update(CRC_HandleTypeDef *hcrytpo_crc, uint8_t *in, uint32_t len);
HAL_StatusTypeDef HAL_CRYPTO_CRC_Final(CRC_HandleTypeDef *hcrytpo_crc, uint32_t *out);

HAL_StatusTypeDef HAL_CRYPTO_AES_Init(psCipherContext_t *ctx, const uint8_t *IV, const uint8_t *key, uint32_t keylen, CRYPTO_MODE cbc);
HAL_StatusTypeDef HAL_CRYPTO_AES_Encrypt_Decrypt(psCipherContext_t *ctx, uint8_t *in, uint8_t *out, uint32_t len, CRYPTO_WAY way);

HAL_StatusTypeDef HAL_CRYPTO_RC4_Init(psCipherContext_t *ctx, uint8_t *key, uint32_t keylen);
HAL_StatusTypeDef HAL_CRYPTO_RC4(psCipherContext_t *ctx, uint8_t *in, uint8_t *out, uint32_t len);

HAL_StatusTypeDef HAL_CRYPTO_3DES_Init(psCipherContext_t *ctx, uint8_t *IV, uint8_t *key, uint32_t keylen, CRYPTO_MODE cbc);
HAL_StatusTypeDef HAL_CRYPTO_3DES_Encrypt_Decrypt(psCipherContext_t *ctx, uint8_t *in, uint8_t *out, uint32_t len, CRYPTO_WAY way);

HAL_StatusTypeDef HAL_CRYPTO_DES_Init(psCipherContext_t *ctx, uint8_t *IV, uint8_t *key, uint32_t keylen, CRYPTO_MODE cbc);
HAL_StatusTypeDef HAL_CRYPTO_DES_Encrypt_Decrypt(psCipherContext_t *ctx, uint8_t *in, uint8_t *out, uint32_t len, CRYPTO_WAY way);

#endif